home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Sounds Terrific 2
/
Sounds Terrific II (1996)(Weird Science)(Disc 1 of 2)[Amiga-PC].iso
/
archives
/
amiga
/
tracker_4_31.lzh
/
tracker
/
Amiga
/
server
/
sound.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-02-13
|
11KB
|
383 lines
/* amiga/server/sound.c */
/* internal operations for the sound server itself */
/* $Id: sound.c,v 1.13 1995/02/13 22:08:26 Espie Exp espie $
* $Log: sound.c,v $
* Revision 1.13 1995/02/13 22:08:26 Espie
* No boolean. Changed include path.
*
* Revision 1.12 1994/01/08 20:26:45 Espie
* Added pause gadget.
*
* Revision 1.11 1994/01/07 15:12:26 Espie
* *** empty log message ***
*
* Revision 1.10 1994/01/07 01:01:49 Espie
* Id.
*
* Revision 1.9 1994/01/05 16:11:43 Espie
* Made TYPE_xxxSYNC explicit.
*
* Revision 1.8 1994/01/05 14:56:02 Espie
* *** empty log message ***
*
* Revision 1.7 1994/01/05 04:35:23 Espie
* Found spurious bug: I had to track through the various
* possibilities of CMD_WRITE to finally realize I was losing my
* messages... So when the queue was empty, I could not allocate
* any channel...
* Needed external program capability back in order though.
* Problem was coming from data faronly, which is very incompatible
* with printf.
*
* Note that now, we only care about reallocating channels when we're
* doing a CMD_WRITE. doing it for ADCMD_PERVOL or CMD_FLUSH is pointless
* since our old data have been completely forgotten in between...
*
* Some tests and masking are probably unnecessary. On the other hand, the
* error code MUST be checked correctly. Maybe I'll try and make the
* CMD_WRITE part clearer.
*
* Revision 1.6 1994/01/05 02:03:14 Espie
* Mostly correct check for losing audio channels.
*
* Revision 1.5 1994/01/04 22:05:35 Espie
* Cosmetic changes, mostly.
*
* Revision 1.4 1994/01/04 20:46:23 Espie
* Plainly working version with all checks...
*
* Revision 1.3 1994/01/04 20:33:20 Espie
* Mostly working version
*
* Revision 1.2 1994/01/04 19:13:21 Espie
* Corrected most of the audio allocation/free muck-up.
*
* Revision 1.1 1994/01/04 15:45:37 Espie
* Initial revision
*
*/
#include <hardware/cia.h>
#include <hardware/intbits.h>
#include <hardware/dmabits.h>
#include <exec/nodes.h>
#include <exec/memory.h>
#include <devices/audio.h>
#include <proto/exec.h>
#include <stddef.h>
#include <stdio.h>
#include "defs.h"
#include "amiga/amiga.h"
#include "amiga/server/server.h"
ID("$Id: sound.c,v 1.13 1995/02/13 22:08:26 Espie Exp espie $")
extern volatile struct CIA __far ciaa;
UBYTE saved_filter, current_filter;
/* we allow for lots more audio requests than we need */
#define QUEUE_LENGTH 50
LOCAL struct ext_audio
{
struct MinNode node;
struct IOAudio request;
}
/* for sending immediate commands */
*immediate = 0;
/* the specific request that gets used for closing/opening */
struct IOAudio *req = 0;
/* the audio queue */
struct MinList queue;
/* keep track of progress */
struct MinList pending;
LOCAL struct MsgPort *aport = 0;
/* in order to clean up afterwards: */
LOCAL int audio_opened = FALSE;
void send_immediate(ULONG command, int mask);
LOCAL void get_requests(void);
/* mask for allocation */
LOCAL UBYTE whichchannel[1];
/* mask of owned channels */
LOCAL UBYTE owned;
/* allocate_channels(mask): sends a request to the audio.device for
* the channels described by mask
*/
LOCAL void allocate_channels(UBYTE mask)
{
whichchannel[0] = mask & ~owned;
req->ioa_Request.io_Command = ADCMD_ALLOCATE;
req->ioa_Data = whichchannel;
req->ioa_Length = sizeof(whichchannel);
req->ioa_Request.io_Flags = ADIOF_NOWAIT | IOF_QUICK;
BeginIO(req);
WaitIO(req);
if (!req->ioa_Request.io_Error) /* update owned channels mask */
{
owned |= (int)req->ioa_Request.io_Unit;
#ifdef EXTERNAL
printf("Allocated: %d (%d) = %d\n", (int)mask, (int)req->ioa_Request.io_Unit, (int)owned);
fflush(stdout);
#endif
}
#ifdef EXTERNAL
else
printf("Failed: %d (%d) = %d\n", req->ioa_Request.io_Error, mask, owned);
#endif
ciaa.ciapra = (ciaa.ciapra & ~ CIAF_LED) | current_filter;
}
/* free_channels(): give back all channels.
*/
LOCAL void free_channels(void)
{
if (req->ioa_AllocKey)
{
req->ioa_Request.io_Command = ADCMD_FREE;
req->ioa_Request.io_Unit = owned;
BeginIO(req);
WaitIO(req);
#ifdef EXTERNAL
printf("Freed !\n");
fflush(stdout);
#endif
owned = 0;
}
}
LOCAL struct ext_audio *create_request(void)
{
struct ext_audio *new;
/* CHECK: no test for failed allocation */
new = AllocMem(sizeof(struct ext_audio), MEMF_CLEAR|MEMF_PUBLIC);
if (req && new)
new->request = *req;
return new;
}
/* actual = create_queue(n): creates a queue of n audio requests,
* returns the actual number
*/
LOCAL int create_queue(int n)
{
int i;
struct ext_audio *new;
for (i = 0; i < n; i++)
{
new = create_request();
if (!new)
return i;
AddTail(&queue, new);
}
return i;
}
/* get back available requests */
LOCAL void get_requests(void)
{
struct IOAudio *back;
while(back = GetMsg(aport))
{
struct ext_audio *full;
full = (struct ext_audio *)
(((UBYTE *)back) - offsetof(struct ext_audio, request));
Remove(full); /* no longer pending */
AddTail(&queue, full); /* ... and available */
}
}
/* send immediate command.
* WARNING: only use send_immediate with commands which
* are GUARANTEED to be synchronous if IOF_QUICK is set
*/
void send_immediate(ULONG command, int mask)
{
immediate->request.ioa_Request.io_Command = command;
immediate->request.ioa_Request.io_Flags = IOF_QUICK;
immediate->request.ioa_Request.io_Unit = (void *)(mask & owned);
immediate->request.ioa_AllocKey = req->ioa_AllocKey;
BeginIO(&immediate->request);
return;
}
void reset_audio(void)
{
send_immediate(CMD_FLUSH, 15);
get_requests();
free_channels();
}
/* obtain_audio(): allocate all the structures we will need to
* play with the audio device
*/
LOCAL void obtain_audio(void)
{
BYTE fail;
aport = CreateMsgPort();
if (!aport)
return;
req = CreateIORequest(aport, sizeof(struct IOAudio));
if (!req)
return;
req->ioa_AllocKey = 0;
req->ioa_Request.io_Message.mn_Node.ln_Pri = 0;
/* Note that OpenDevice returns 0 on success
*/
fail = OpenDevice("audio.device", 0L, (struct IORequest *)req, 0L);
if (!fail)
audio_opened = TRUE;
}
struct MsgPort *start_audio(void)
{
NewList(&queue); /* initialize these now for correct cleanup */
NewList(&pending);
owned = 0; /* we own no channel right now */
obtain_audio();
if (!audio_opened || create_queue(QUEUE_LENGTH) < QUEUE_LENGTH)
return 0;
immediate = RemHead(&queue);
saved_filter = ciaa.ciapra & CIAF_LED;
current_filter = CIAF_LED;
return aport;
}
void end_audio()
{
struct ext_audio *sweep, *next;
if (immediate) /* get immediate back in queue for freeing it */
AddTail(&queue, immediate);
if (req)
free_channels();
get_requests();
/* REMOVE ALL REQUESTS FROM THE PENDING LIST */
SCANLIST(sweep, next, &pending, struct ext_audio *)
{
AbortIO(&sweep->request);
WaitIO(&sweep->request);
}
/* Now we can close safely */
if (audio_opened)
CloseDevice((struct IORequest *)req);
if (req)
DeleteIORequest(req);
if (aport)
DeletePort(aport);
SCANLIST(sweep, next, &queue, struct ext_audio *)
FreeMem(sweep, sizeof(struct ext_audio));
ciaa.ciapra = (ciaa.ciapra & ~CIAF_LED) | saved_filter;
}
/* Perform musical events pertaining to the current time */
void do_events(struct List *e)
{
struct ext_message *msg, *msg2;
while (msg = RemHead(e))
{
switch (msg->type)
{
case TYPE_WAIT: /* next time to wait for: finished */
AddHead(e, msg);
return;
case TYPE_FLUSH_CHANNEL:
send_immediate(CMD_FLUSH, msg->data.info.channel_mask);
break;
case TYPE_SETUP: /* setup is a two message command */
msg2 = RemHead(e);
if (msg2)
{
struct ext_audio *new;
new = RemHead(&queue);
if (new)
{
new->request.ioa_Request.io_Command = CMD_WRITE;
if (msg2->data.info.pitch)
{
new->request.ioa_Request.io_Flags = ADIOF_PERVOL | IOF_QUICK;
new->request.ioa_Period = msg2->data.info.pitch;
new->request.ioa_Volume = msg2->data.info.volume;
}
else
new->request.ioa_Request.io_Flags = IOF_QUICK;
if ((owned & msg2->data.info.channel_mask) == 0)
allocate_channels(msg2->data.info.channel_mask);
new->request.ioa_Request.io_Unit = msg2->data.info.channel_mask & owned;
new->request.ioa_Cycles = msg2->data.info.cycle;
new->request.ioa_Data = msg->data.sample.start;
new->request.ioa_Length= msg->data.sample.length;
new->request.ioa_AllocKey = req->ioa_AllocKey;
if (new->request.ioa_Request.io_Unit)
{
BeginIO(&new->request);
if (new->request.ioa_Request.io_Flags & IOF_QUICK)
{
AddTail(&queue, new);
if (new->request.ioa_Request.io_Error)
{
owned &=~ msg2->data.info.channel_mask;
#ifdef EXTERNAL
printf("Lost: %d (%d) = %d\n", new->request.ioa_Request.io_Error, msg2->data.info.channel_mask, owned);
fflush(stdout);
#endif
}
}
else
AddTail(&pending, new);
}
else
AddTail(&queue, new);
}
#ifdef EXTERNAL
else
printf("No new\n");
#endif
ReplyMsg(msg2);
}
break;
case TYPE_CHANGE:
immediate->request.ioa_Period = msg->data.info.pitch;
immediate->request.ioa_Volume = msg->data.info.volume;
send_immediate(ADCMD_PERVOL, msg->data.info.channel_mask);
break;
case TYPE_COMM:
case TYPE_SYNC:
case TYPE_SYNC_DO:
/* nothing to do there */
break;
default:
/* not implemented yet */
break;
}
ReplyMsg(msg);
get_requests();
}
}
void handle_audio(struct List *l, int signaled)
{
get_requests();
}